#include "Mesh.h"


Mesh::Mesh(void)
	:m_pDeivce(NULL)
	,m_strName("NoDefine")
	,m_iMeshID(-1)
	,m_iNumBones(0)
	,m_iNumVerteices(0)
	,m_iNumFaces(0)
	,m_pVertexBuffer(NULL)
	,m_pIndexBuffer(NULL)
{
}


Mesh::~Mesh(void)
{
	ReleaseCOM(m_pVertexBuffer);
	ReleaseCOM(m_pIndexBuffer);
}

ID3D10Buffer* Mesh::GetVertexBuffer()
{
	//return NULL;
	return m_pVertexBuffer;
}

ID3D10Buffer* Mesh::GetIndexBuffer()
{
	//return NULL;
	return m_pIndexBuffer;
}

MaterialInfo* Mesh::GetMaterialInfo()
{
	return &m_MaterialInfo;
}

int Mesh::GetNumVerteices()
{
	return m_iNumVerteices;
}

void Mesh::BuildVertexBuffer()
{
	D3D10_BUFFER_DESC vbd;
	vbd.Usage = D3D10_USAGE_IMMUTABLE;
	vbd.ByteWidth = sizeof(MeshVertex) * m_iNumVerteices;
	vbd.BindFlags = D3D10_BIND_VERTEX_BUFFER;
	vbd.CPUAccessFlags = 0;
	vbd.MiscFlags = 0;
	D3D10_SUBRESOURCE_DATA vinitData;
	//init from std::vector need to do like this
	vinitData.pSysMem = &m_lstVertex[0];
	HR(m_pDeivce->CreateBuffer(&vbd, &vinitData, &m_pVertexBuffer));
}

void Mesh::BuildIndexBuffer()
{
	D3D10_BUFFER_DESC ibd;
	ibd.Usage = D3D10_USAGE_IMMUTABLE;
	ibd.ByteWidth = sizeof(DWORD) * m_iNumFaces*3;
	ibd.BindFlags = D3D10_BIND_INDEX_BUFFER;
	ibd.CPUAccessFlags = 0;
	ibd.MiscFlags = 0;
	D3D10_SUBRESOURCE_DATA iinitData;
	//init from std::vector need to do like this
	iinitData.pSysMem = &m_lstIndex[0];
	HR(m_pDeivce->CreateBuffer(&ibd, &iinitData, &m_pIndexBuffer));
}

int Mesh::GetNumFaces()
{
	return m_iNumFaces;
}

bool Mesh::Intersect( const Ray& ray )
{
	//the algorithm come from 
	//http://courses.csusm.edu/cs697exz/ray_box.htm

	float t1,t2;
	float f_tNear = MIN_FLOAT , f_tFar = MAX_FLOAT;

	//check the x plane
	if(ray.m_vec3Dir.x == 0)
	{
		//the ray parallel with the x axis
		if(ray.m_vec3Pos.x < m_BoundingBox.m_vec3Min.x
			|| ray.m_vec3Pos.x > m_BoundingBox.m_vec3Max.x)
		{
			return false;
		}
	}
	else
	{
		//not parallel with the x axis
		t1 = (m_BoundingBox.m_vec3Min.x - ray.m_vec3Pos.x) / ray.m_vec3Dir.x;
		t2 = (m_BoundingBox.m_vec3Max.x - ray.m_vec3Pos.x) / ray.m_vec3Dir.x;

		if(t1>t2) std::swap(t1,t2);
		if(t1 > f_tNear) f_tNear = t1;
		if(t2 < f_tFar) f_tFar = t2;

		//box is missed so return false 
		if(f_tNear > f_tFar)	return false;
		//box is behind ray so return false
		if(f_tFar < 0)	return false;
	}

	//check the y plane
	if(ray.m_vec3Dir.y == 0)
	{
		//the ray parallel with the y axis
		if(ray.m_vec3Pos.y < m_BoundingBox.m_vec3Min.y
			|| ray.m_vec3Pos.y > m_BoundingBox.m_vec3Max.y)
		{
			return false;
		}
	}
	else
	{
		//not parallel with the y axis
		t1 = (m_BoundingBox.m_vec3Min.y - ray.m_vec3Pos.y) / ray.m_vec3Dir.y;
		t2 = (m_BoundingBox.m_vec3Max.y - ray.m_vec3Pos.y) / ray.m_vec3Dir.y;

		if(t1>t2) std::swap(t1,t2);
		if(t1 > f_tNear) f_tNear = t1;
		if(t2 < f_tFar) f_tFar = t2;

		//box is missed so return false 
		if(f_tNear > f_tFar)	return false;
		//box is behind ray so return false
		if(f_tFar < 0)	return false;
	}

	//check the z plane
	if(ray.m_vec3Dir.z == 0)
	{
		//the ray parallel with the z axis
		if(ray.m_vec3Pos.z < m_BoundingBox.m_vec3Min.z
			|| ray.m_vec3Pos.z > m_BoundingBox.m_vec3Max.z)
		{
			return false;
		}
	}
	else
	{
		//not parallel with the z axis
		t1 = (m_BoundingBox.m_vec3Min.z - ray.m_vec3Pos.z) / ray.m_vec3Dir.z;
		t2 = (m_BoundingBox.m_vec3Max.z - ray.m_vec3Pos.z) / ray.m_vec3Dir.z;

		if(t1>t2) std::swap(t1,t2);
		if(t1 > f_tNear) f_tNear = t1;
		if(t2 < f_tFar) f_tFar = t2;

		//box is missed so return false 
		if(f_tNear > f_tFar)	return false;
		//box is behind ray so return false
		if(f_tFar < 0)	return false;
	}

	//All tests were survived, so return TRUE 
	return true;
}

void Mesh::BuildBoundingBox()
{
	m_BoundingBox.m_vec3Min = D3DXVECTOR3(MAX_FLOAT,MAX_FLOAT,MAX_FLOAT);
	m_BoundingBox.m_vec3Max = D3DXVECTOR3(MIN_FLOAT,MIN_FLOAT,MIN_FLOAT);

	for(int i=0 ;i<m_iNumVerteices ;++i)
	{
		D3DXVec3Minimize(&m_BoundingBox.m_vec3Min ,&m_BoundingBox.m_vec3Min ,&m_lstVertex[i].pos);
		D3DXVec3Maximize(&m_BoundingBox.m_vec3Max ,&m_BoundingBox.m_vec3Max ,&m_lstVertex[i].pos);
	}

	m_vec3CenterPoint.x = (m_BoundingBox.m_vec3Max.x + m_BoundingBox.m_vec3Min.x) / 2;
	m_vec3CenterPoint.y = (m_BoundingBox.m_vec3Max.y + m_BoundingBox.m_vec3Min.y) / 2;
	m_vec3CenterPoint.z = (m_BoundingBox.m_vec3Max.z + m_BoundingBox.m_vec3Min.z) / 2;
}

D3DXVECTOR3 Mesh::GetCenterPoint()
{
	return m_vec3CenterPoint;
}
